﻿using System;
using System.Drawing;
using System.Windows.Forms;
using LuaVM.Core;

namespace Plugin.Input
{
    public class InputPlugin : LuaDllPlugin
	{
		public override string Name => "Input";		

		private LuaTable m_keys = null;
        private LuaTable m_buttons = null;		

		public override string[] ExportedFunctions => new string[] {
			"KeyDown",
			"KeyUp",
			"KeyStoke",
			"SendKeys",
			"IsKeyDown",
			"ReleaseAllKeys",
			"GetCursorPos",
			"SetCursorPos",
			"MouseDown",
			"MouseUp",
			"MouseClick",
			"MouseDrag",
			"MouseWheel"
		};

		protected override void OnAttach()
		{
			base.OnAttach();

			m_keys = NewTable();
			m_keys.CopyEnum<Keys>(true);

			m_buttons = NewTable();
			m_buttons.CopyEnum<MouseButtons>(true);

			RegisterFunction(this, "KeyDown");
			RegisterFunction(this, "KeyUp");
			RegisterFunction(this, "KeyStoke");
			RegisterFunction<InputPlugin>("SendKeys");
			RegisterFunction(this, "IsKeyDown");
			RegisterFunction<InputPlugin>("ReleaseAllKeys");
			RegisterFunction<InputPlugin>("GetCursorPos");
			RegisterFunction<InputPlugin>("SetCursorPos");
			RegisterFunction(this, "MouseDown");
			RegisterFunction(this, "MouseUp");
			RegisterFunction(this, "MouseClick");
			RegisterFunction(this, "MouseDrag");
			RegisterFunction(this, "MouseWheel");
		}			

		public void KeyDown(string key, string mods = null)
		{
			Win32API.Input.KeyDown(FindKey(key), ParseMods(mods));
		}

		public void KeyUp(string key, string mods = null)
		{
			Win32API.Input.KeyUp(FindKey(key), ParseMods(mods));
		}

		public void KeyStoke(string key, string mods = null)
		{
			Win32API.Input.KeyStroke(FindKey(key), ParseMods(mods));
		}

		public static void SendKeys(string keys)
		{
			Win32API.Input.KeyStroke(keys);
		}

		public bool IsKeyDown(string key)
		{
			return Win32API.Input.IsKeyDown(FindKey(key));
		}

		public static void ReleaseAllKeys()
		{
			Win32API.Input.ReleaseAllKeys();
		}

		public static int GetCursorPos(out int y)
		{
			Point pt = Win32API.Input.GetCursorPos();
			y = pt.Y;
			return pt.X;
		}

		public static void SetCursorPos(int x, int y)
		{
			Win32API.Input.SetCursorPos(x, y);
		}

		public void MouseDown(string button = null)
		{
			Win32API.Input.MouseDown(GetButton(button));
		}

		public void MouseUp(string button = null)
		{
			Win32API.Input.MouseUp(GetButton(button));
		}

		public void MouseClick(string button = null)
		{
			Win32API.Input.MouseClick(GetButton(button));
		}

		public void MouseDrag(int x1, int y1, int x2, int y2, string button = null)
		{
			Win32API.Input.MouseDrag(x1, y1, x2, y2, GetButton(button));
		}

		public void MouseWheel(bool scrollUp = false)
		{
			Win32API.Input.MouseWheel(scrollUp);
		}

		private Keys FindKey(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return Keys.None;
			}

			object value = m_keys[name.ToLower()];
			if (value == null)
			{
				return Keys.None;
			}

			return (Keys)value;
		}

		private Keys ParseMods(string mods)
		{
			if (string.IsNullOrEmpty(mods))
			{
				return Keys.None; ;
			}

			Keys value = Keys.None;
			string[] items = mods.Split(new char[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < items.Length; i++)
			{
				string name = items[i].Trim();
				Keys mod = FindKey(name);
				if (mod != Keys.None)
				{
					value |= mod;
				}
			}

			return value;
		}

		private MouseButtons GetButton(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return MouseButtons.Left;
			}

			object value = m_buttons[name.ToLower()];
			if (value == null)
			{
				return MouseButtons.Left;
			}

			return (MouseButtons)value;
		}
	}
}
